package framework.aop.proxy;

import framework.aop.intercept.InchMethodInvocation;
import framework.aop.support.InchAdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
 * java jdk dynamic proxy
 */
public class InchJdkDynamicAopProxy implements InchAopProxy, InvocationHandler {

    private InchAdvisedSupport config;

    /**
     * constructor
     * @param config InchAdviseSupport instance
     */
    public InchJdkDynamicAopProxy(InchAdvisedSupport config) {
        this.config = config;
    }

    /**
     * get proxy without param
     * classloader normally in a project is the same(not so sure)
     *
     * @return instance of proxy
     */
    @Override
    public Object getProxy() {
        return getProxy(this.config.getTargetClass().getClassLoader());
    }

    /**
     * get proxy with classLoader
     * @param classLoader the class loader
     * @return instance of proxy
     */
    @Override
    public Object getProxy(ClassLoader classLoader) {
        Object instance = Proxy.newProxyInstance(classLoader,this.config.getTargetClass().getInterfaces(),this);
        return instance;
    }

    /**
     * when spring mvc do normal invoke it goes into here send all info from InchAdviseSupport to
     * IncMethodInvocation to execute
     *
     * @param proxy proxy instance
     * @param method the method
     * @param args arguments
     * @return the result of the point cut method
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //get all the advises
        List<Object> interceptorsAndDynamicMethodMatchers =
                config.getInterceptorsAndDynamicInterceptionAdvice(method,this.config.getTargetClass());
        //give advise to method invocation to execute one by one
        InchMethodInvocation methodInvocation =
                new InchMethodInvocation(proxy,method,this.config.getTarget(),this.config.getTargetClass(),args,interceptorsAndDynamicMethodMatchers);
        //run it
        return methodInvocation.proceed();
    }
}
